﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Sinacor.Infra.UI.Controls.SmartClient;
using System.Windows.Controls.Primitives;
using System.Collections;
using System.Linq;
using System.Windows.Media;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
    public class SinacorListView : ListView, IItemsControlDragSource, IItemsControlDropTarget
	{
        public SinacorListView()
        {
            // BufferedEvent
            _bufferedSelectionChangedEventManager = new BufferedEventManager<SelectionChangedEventArgs>();
            this.SelectionChanged += _bufferedSelectionChangedEventManager.EventCapturer;
            _bufferedSelectionChangedEventManager.AddBufferedEventListener(this, OnBufferedSelectionChanged);

            DragDropManager dragDropManager = new DragDropManager(this);

            this.Loaded += new RoutedEventHandler(SinacorListView_Loaded);
            this.Unloaded += new RoutedEventHandler(SinacorListView_Unloaded);
        }

        #region Tratamento de eventos

        private void SinacorListView_Loaded(object sender, RoutedEventArgs e)
        {
            _bufferedSelectionChangedEventManager.Start();
        }
        private void SinacorListView_Unloaded(object sender, RoutedEventArgs e)
        {
            _bufferedSelectionChangedEventManager.Stop();
        }

        #endregion
        
        #region Selection

        #region ConfirmSelectionEvent
        public static readonly RoutedEvent ConfirmSelectionEvent = EventManager.RegisterRoutedEvent("ConfirmSelection", RoutingStrategy.Bubble, typeof(ItemEventHandler), typeof(SinacorListView));
        /// <summary>
        /// Evento disparado quando o usuário confima a seleção de um item
        /// </summary>
        public event ItemEventHandler ConfirmSelection
        {
            add { AddHandler(ConfirmSelectionEvent, value); }
            remove { RemoveHandler(ConfirmSelectionEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ConfirmSelection</c>
        /// </summary>
        /// <param name="element">Elemento que vai disparar o evento</param>
        /// <param name="index">Índice do item</param>
        /// <param name="item">Item</param>
        protected virtual void OnConfirmSelection(int index, object item)
        {
            ItemEventArgs e = new ItemEventArgs(ConfirmSelectionEvent, this, new ItemInfo(index, item));
            this.RaiseEvent(e);
        }
        #endregion

        #region BufferedSelectionChangedEvent
        private BufferedEventManager<SelectionChangedEventArgs> _bufferedSelectionChangedEventManager;

        public static readonly RoutedEvent BufferedSelectionChangedEvent = EventManager.RegisterRoutedEvent("BufferedSelectionChanged", RoutingStrategy.Bubble, typeof(BufferedEventHandler<SelectionChangedEventArgs>), typeof(SinacorListView));
        /// <summary>
        /// Evento buferizado de SelectionChanged
        /// </summary>
        public event BufferedEventHandler<SelectionChangedEventArgs> BufferedSelectionChanged
        {
            add { AddHandler(BufferedSelectionChangedEvent, value); }
            remove { RemoveHandler(BufferedSelectionChangedEvent, value); }
        }

        protected virtual void OnBufferedSelectionChanged(object sender, SelectionChangedEventArgs originalEventArgs, int eventCount)
        {
            BufferedEventArgs<SelectionChangedEventArgs> e = new BufferedEventArgs<SelectionChangedEventArgs>(BufferedSelectionChangedEvent, originalEventArgs, eventCount);
            this.RaiseEvent(e);
        }
        #endregion

        #endregion

        #region DragDrop

        #region IItemsControlDragSource Members

        IList IItemsControlDragSource.GetDraggedItems()
        {
            return this.SelectedItems;
        }

        #endregion

        #endregion

		protected override DependencyObject GetContainerForItemOverride()
		{
			return new SinacorListViewItem();
		}

		protected override bool IsItemItsOwnContainerOverride(object item)
		{
			return (item is SinacorListViewItem);
		}
	}

    public class SinacorListViewItem : ListViewItem, IItemContainerDragSource, IItemContainerDropTarget
    {
        public SinacorListViewItem()
        {
            DragDropManager dragDropManager = new DragDropManager(this);
        }

        public int GetIndex()
        {
            ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(this);
            return itemsControl != null ? itemsControl.ItemContainerGenerator.IndexFromContainer(this) : -1;
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if (e.Key == Key.Enter)
            {
                this.OnConfirmSelection(this.GetIndex(), this.DataContext);
                e.Handled = true;
            }
        }

        protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
            this.OnConfirmSelection(this.GetIndex(), this.DataContext);

            base.OnMouseDoubleClick(e);
        }

        #region ConfirmSelection
        public static readonly RoutedEvent ConfirmSelectionEvent = SinacorListView.ConfirmSelectionEvent.AddOwner(typeof(SinacorListViewItem));
        /// <summary>
        /// Evento disparado quando o usuário confima a seleção de um item
        /// </summary>
        public event ItemEventHandler ConfirmSelection
        {
            add { AddHandler(ConfirmSelectionEvent, value); }
            remove { RemoveHandler(ConfirmSelectionEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ConfirmSelection</c>
        /// </summary>
        /// <param name="element">Elemento que vai disparar o evento</param>
        /// <param name="index">Índice do item</param>
        /// <param name="item">Item</param>
        protected virtual void OnConfirmSelection(int index, object item)
        {
            ItemEventArgs e = new ItemEventArgs(ConfirmSelectionEvent, this, new ItemInfo(index, item));
            this.RaiseEvent(e);
        }
        #endregion

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            e.Handled = true;
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            base.OnMouseLeftButtonUp(e);
        }

        #region IDragSource Members

        FrameworkElement IDragSource.GetDraggedContent()
        {
            return this;
        }

        #endregion

        #region IItemContainerDragSource Members

        bool IItemContainerDragSource.IsDragging
        {
            get { return this.IsSelected; }
        }

        IItemsControlDragSource IItemContainerDragSource.GetItemsControl()
        {
            return ItemsControl.ItemsControlFromItemContainer(this) as IItemsControlDragSource;
        }

        #endregion
    }
}